home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
mint104s.zoo
/
mint.src
/
mem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-08
|
39KB
|
1,658 lines
/*
Copyright 1990,1991,1992 Eric R. Smith.
Copyright 1992,1993 Atari Corporation.
All rights reserved.
*/
/*
* mem.c:: routines for managing memory regions
*/
#include "mint.h"
#include "fasttext.h" /* for line A stuff */
#ifndef VgetSize
extern long xbios();
#define VgetSize(mode) xbios(91, (short)(mode))
#define Vsetmode(mode) xbios(88, (short)(mode))
#endif
static long core_malloc P_((long, int));
static void core_free P_((long));
/* macro for testing whether a memory region is free */
#define ISFREE(m) ((m)->links == 0)
/*
* list of shared text regions currently being executed
*/
SHTEXT *text_reg = 0;
/*
* initialize memory routines
*/
/* initial number of memory regions */
#define NREGIONS 512
/* number of new regions to allocate when the initial ones are used up */
#define NEWREGIONS 256
static MEMREGION use_regions[NREGIONS+1];
MEMREGION *rfreelist;
/* these variables are set in init_core(), and used in
* init_mem()
*/
static ulong scrnsize, scrnplace;
static SCREEN *vscreen;
void
init_mem()
{
int i;
MEMREGION *r;
long newbase;
use_regions[NREGIONS].next = 0;
for (i = 0; i < NREGIONS; i++) {
use_regions[i].next = &use_regions[i+1];
}
rfreelist = use_regions;
init_core();
init_swap();
init_tables(); /* initialize MMU constants */
/* mark all the regions in the core & alt lists as "invalid" */
for (r = *core; r; r = r->next) {
mark_region(r,PROT_I);
}
for (r = *alt; r; r = r->next) {
mark_region(r,PROT_I);
}
/* make sure the screen is set up properly */
newbase = s_realloc(scrnsize);
/* if we did get a new screen, point the new screen
* at the right place after copying the data
* if possible, save the screen to another buffer,
* since if the new screen and old screen overlap
* the blit will look very ugly.
* Note that if the screen isn't moveable, then we set
* scrnsize to a ridiculously large value, and so the
* s_realloc above failed.
*/
if (newbase) {
/* find a free region for temp storage */
for (r = *core; r; r = r->next) {
if (ISFREE(r) && r->len >= scrnsize)
break;
}
if (r) {
quickmove((char *)r->loc, (char *)scrnplace, scrnsize);
Setscreen((void *)r->loc, (void *)r->loc, -1);
Vsync();
quickmove((char *)newbase, (char *)r->loc, scrnsize);
} else {
quickmove((char *)newbase, (char *)scrnplace, scrnsize);
}
Setscreen((void *)newbase, (void *)newbase, -1);
/* fix the cursor */
Cconws("\r\n");
}
}
/*
* init_core(): initialize the core memory map (normal ST ram) and also
* the alternate memory map (fast ram on the TT)
*/
static MEMREGION *_core_regions = 0, *_alt_regions = 0,
*_ker_regions = 0;
MMAP core = &_core_regions;
MMAP alt = &_alt_regions;
MMAP ker = &_ker_regions;
/* note: add_region must adjust both the size and starting
* address of the region being added so that memory is
* always properly aligned
*/
int
add_region(map, place, size, mflags)
MMAP map;
ulong place, size;
unsigned mflags; /* initial flags for region */
{
MEMREGION *m;
ulong trimsize;
TRACELOW(("add_region(map=%lx,place=%lx,size=%lx,flags=%x)",
map,place,size,mflags));
m = new_region();
if (m == 0)
return 0; /* failure */
m->links = 0;
if (place & MASKBITS) {
/* increase place & shorten size by the amount we're trimming */
trimsize = (MASKBITS+1) - (place & MASKBITS);
if (size <= trimsize) goto lose;
size -= trimsize;
place += trimsize;
}
/* now trim size DOWN to a multiple of pages */
if (size & MASKBITS) size &= ~MASKBITS;
/* only add if there's anything left */
if (size) {
m->len = size;
m->loc = place;
m->next = *map;
m->mflags = mflags;
*map = m;
}
else {
/* succeed but don't do anything; dispose of region */
lose: dispose_region(m);
}
return 1; /* success */
}
static long
core_malloc(amt, mode)
long amt;
int mode;
{
static int mxalloc = -1; /* does GEMDOS know about Mxalloc? */
long ret;
if (mxalloc < 0) {
ret = (long)Mxalloc(-1L, 0);
if (ret == -32) mxalloc = 0; /* unknown function */
else if (ret >= 0) mxalloc = 1;
else {
ALERT("GEMDOS returned %ld from Mxalloc", ret);
mxalloc = 0;
}
}
if (mxalloc)
return Mxalloc(amt, mode);
else if (mode == 1)
return 0L;
else
return Malloc(amt);
}
static void
core_free(where)
long where;
{
Mfree((void *)where);
}
void
init_core()
{
extern int FalconVideo; /* set in main.c */
int scrndone = 0;
ulong size;
ulong place;
ulong temp;
void *tossave;
tossave = (void *)core_malloc((long)TOS_MEM, 0);
if (!tossave) {
FATAL("Not enough memory to run MiNT");
}
/* initialize kernel memory */
place = (ulong)core_malloc(KERNEL_MEM, 3);
if (place != 0) {
nalloc_arena_add((void *)place,KERNEL_MEM);
}
/*
* find out where the screen is. We want to manage the screen
* memory along with all the other memory, so that Srealloc()
* can be used by the XBIOS to allocate screens from the
* end of memory -- this avoids fragmentation problems when
* changing resolutions.
*/
/* Note, however, that some graphics boards (e.g. Matrix)
* are unable to change the screen address. We fake out the
* rest of our code by pretending to have a really huge
* screen that can't be changed.
*/
scrnplace = (long)Physbase();
vscreen = (SCREEN *)((char *)lineA0() - 346);
if (FalconVideo) {
/* the Falcon can tell us the screen size */
scrnsize = VgetSize(Vsetmode(-1));
} else {
/* otherwise, use the line A variables */
scrnsize = (vscreen->maxy+1)*(long)vscreen->linelen;
}
/* check for a graphics card with fixed screen location */
#define phys_top_st (*(ulong *)0x42eL)
if (scrnplace >= phys_top_st) {
/* screen isn't in ST RAM */
scrnsize = 0x7fffffffUL;
scrndone = 1;
} else {
temp = (ulong)core_malloc(scrnsize+256L, 0);
if (temp) {
(void)Setscreen((void *)-1L,
(void *)((temp+511)&(0xffffff00L)), -1);
if ((long)Physbase() != (temp+511)&(0xffffff00L)) {
scrnsize = 0x7fffffffUL;
scrndone = 1;
}
(void)Setscreen((void *)-1L, (void *)scrnplace, -1);
core_free(temp);
}
}
/* initialize ST RAM */
size = (ulong)core_malloc(-1L, 0);
while (size > 0) {
place = (ulong)core_malloc(size, 0);
if (place + size == scrnplace) {
size += scrnsize;
scrndone = 1;
}
if (!add_region(core, place, size, M_CORE))
FATAL("init_mem: unable to add a region");
size = (ulong)core_malloc(-1L, 0);
}
if (!scrndone) {
(void)add_region(core, scrnplace, scrnsize, M_CORE);
}
/* initialize alternate RAM */
size = (ulong)core_malloc(-1L, 1);
while (size > 0) {
place = (ulong)core_malloc(size, 1);
if (!add_region(alt, place, size, M_ALT))
FATAL("init_mem: unable to add a region");
size = (ulong)core_malloc(-1L, 1);
}
(void)Mfree(tossave); /* leave some memory for TOS to use */
}
/*
* init_swap(): initialize the swap area; for now, this does nothing
*/
MEMREGION *_swap_regions = 0;
MMAP swap = &_swap_regions;
void
init_swap()
{
}
/*
* routines for allocating/deallocating memory regions
*/
/*
* new_region returns a new memory region descriptor, or NULL
*/
MEMREGION *
new_region()
{
MEMREGION *m, *newfrees;
int i;
m = rfreelist;
if (!m) {
ALERT("new_region: ran out of free regions");
return 0;
}
assert(ISFREE(m));
rfreelist = m->next;
m->next = 0;
/* if we're running low on free regions, allocate some more
* we have to do this with at least 1 free region left so that get_region
* has a chance of working
*/
if (rfreelist && !rfreelist->next) {
MEMREGION *newstuff;
TRACELOW(("get_region: getting new region descriptors"));
newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
if (!newstuff)
newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
if (!newstuff)
newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION